mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
first version of the rust bindings: parsing and rendering is mostly functional
This commit is contained in:
parent
9d7ad2a67f
commit
dd62ec934c
10 changed files with 1208 additions and 0 deletions
6
rust/Cargo.toml
Normal file
6
rust/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "psyc"
|
||||||
|
version = "1.0.0"
|
||||||
|
links = "psyc"
|
||||||
|
build = "build.rs"
|
||||||
|
description = "rust bindings for libpsyc"
|
18
rust/build.rs
Normal file
18
rust/build.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use std::env;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::path::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Command::new("make")
|
||||||
|
.arg("-C")
|
||||||
|
.arg("..")
|
||||||
|
.output()
|
||||||
|
.unwrap_or_else(|e| panic!("failed to execute process: {}", e));
|
||||||
|
|
||||||
|
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
let path = Path::new(&manifest_dir).parent().unwrap().join("lib");
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-search=native={}", path.display());
|
||||||
|
println!("cargo:rerun-if-changed={}", path.display());
|
||||||
|
println!("cargo:rustc-link-lib=static=psyc");
|
||||||
|
}
|
9
rust/src/lib.rs
Normal file
9
rust/src/lib.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
mod types;
|
||||||
|
pub mod parser_types;
|
||||||
|
pub mod packet_types;
|
||||||
|
pub mod parser;
|
||||||
|
pub mod packet;
|
||||||
|
|
||||||
|
pub use parser::*;
|
||||||
|
pub use packet::*;
|
347
rust/src/packet.rs
Normal file
347
rust/src/packet.rs
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
use types::*;
|
||||||
|
use packet_types::*;
|
||||||
|
use std::mem;
|
||||||
|
use std::ptr;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
/// functions from packet.h
|
||||||
|
fn psyc_num_length(n: usize) -> usize;
|
||||||
|
fn psyc_modifier_length_check(m: *const RawPsycModifier) -> PsycModifierFlag;
|
||||||
|
fn psyc_modifier_init(m: *mut RawPsycModifier,
|
||||||
|
oper: PsycOperator,
|
||||||
|
name: *const c_char,
|
||||||
|
namelen: usize,
|
||||||
|
value: *const c_char,
|
||||||
|
valuelen: usize,
|
||||||
|
flag: PsycModifierFlag);
|
||||||
|
|
||||||
|
fn psyc_elem_length_check(value: *const PsycString, end: c_char) -> PsycElemFlag;
|
||||||
|
fn psyc_elem_length(elem: *const PsycElem) -> usize;
|
||||||
|
fn psyc_dict_key_length(elem: *const PsycDictKey) -> usize;
|
||||||
|
fn psyc_list_length_set(list: *mut RawPsycList) -> usize;
|
||||||
|
fn psyc_dict_length_set(dict: *mut RawPsycDict) -> usize;
|
||||||
|
fn psyc_modifier_length(m: *const RawPsycModifier) -> usize;
|
||||||
|
fn psyc_packet_length_check(p: *const RawPsycPacket) -> PsycPacketFlag;
|
||||||
|
fn psyc_packet_length_set(p: *mut RawPsycPacket) -> usize;
|
||||||
|
fn psyc_list_init(list: *mut RawPsycList, elems: *const PsycElem, num_elems: usize);
|
||||||
|
fn psyc_dict_init(dict: *mut RawPsycDict, elems: *const PsycDictElem, num_elems: usize);
|
||||||
|
fn psyc_packet_init(packet: *mut RawPsycPacket,
|
||||||
|
routing: *const RawPsycModifier,
|
||||||
|
routinglen: usize,
|
||||||
|
entity: *const RawPsycModifier,
|
||||||
|
entitylen: usize,
|
||||||
|
method: *const c_char,
|
||||||
|
methodlen: usize,
|
||||||
|
data: *const c_char,
|
||||||
|
datalen: usize,
|
||||||
|
stateop: c_char,
|
||||||
|
flag: PsycPacketFlag);
|
||||||
|
|
||||||
|
fn psyc_packet_init_raw(packet: *mut RawPsycPacket,
|
||||||
|
routing: *const RawPsycModifier,
|
||||||
|
routinglen: usize,
|
||||||
|
content: *const c_char,
|
||||||
|
contentlen: usize,
|
||||||
|
flag: PsycPacketFlag);
|
||||||
|
|
||||||
|
fn psyc_packet_id(list: *mut RawPsycList,
|
||||||
|
elems: *mut PsycElem,
|
||||||
|
context: *const c_char,
|
||||||
|
contextlen: usize,
|
||||||
|
source: *const c_char,
|
||||||
|
sourcelen: usize,
|
||||||
|
target: *const c_char,
|
||||||
|
targetlen: usize,
|
||||||
|
counter: *const c_char,
|
||||||
|
counterlen: usize,
|
||||||
|
fragment: *const c_char,
|
||||||
|
fragmentlen: usize);
|
||||||
|
|
||||||
|
/// functions from render.h
|
||||||
|
fn psyc_render(packet: *const RawPsycPacket, buffer: *mut c_char, buflen: usize) -> PsycRenderRC;
|
||||||
|
fn psyc_render_modifier(modifier: *const RawPsycModifier, buffer: *mut c_char) -> usize;
|
||||||
|
fn psyc_render_elem(elem: *const PsycElem, buffer: *mut c_char, buflen: usize) -> PsycRenderRC;
|
||||||
|
fn psyc_render_dict_key(elem: *const PsycDictKey, buffer: *mut c_char, buflen: usize) -> PsycRenderRC;
|
||||||
|
fn psyc_render_list(list: *const RawPsycList, buffer: *mut c_char, buflen: usize) -> PsycRenderRC;
|
||||||
|
fn psyc_render_dict(dict: *const RawPsycDict, buffer: *mut c_char, buflen: usize) -> PsycRenderRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycList {
|
||||||
|
rendered_list: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycDict {
|
||||||
|
rendered_dict: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycModifier<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
value: &'a [u8],
|
||||||
|
operator: PsycOperator,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycPacket<'a> {
|
||||||
|
raw_packet: RawPsycPacket,
|
||||||
|
routing_modifiers: &'a [PsycModifier<'a>],
|
||||||
|
entity_modifiers: &'a [PsycModifier<'a>],
|
||||||
|
raw_routing_modifiers: Vec<RawPsycModifier>,
|
||||||
|
raw_entity_modifiers: Vec<RawPsycModifier>,
|
||||||
|
method: &'a str,
|
||||||
|
body: &'a [u8]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum PsycRenderError {
|
||||||
|
MethodMissing = PsycRenderRC::PSYC_RENDER_ERROR_METHOD_MISSING as _,
|
||||||
|
ModifierNameMissing = PsycRenderRC::PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING as _,
|
||||||
|
GenericError = PsycRenderRC::PSYC_RENDER_ERROR as _
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PsycList {
|
||||||
|
/// Construct a PsycList from a list of byte lists
|
||||||
|
pub fn new(list: &[&[u8]]) -> Self {
|
||||||
|
let mut psyc_list: RawPsycList;
|
||||||
|
let elements: Vec<PsycElem>;
|
||||||
|
let mut buffer: Vec<u8>;
|
||||||
|
unsafe {
|
||||||
|
psyc_list = mem::uninitialized();
|
||||||
|
let psyc_list_ptr = &mut psyc_list as *mut RawPsycList;
|
||||||
|
elements = list.iter().map(|e| make_psyc_elem(&e)).collect();
|
||||||
|
let elements_ptr = elements.as_ptr() as *const PsycElem;
|
||||||
|
psyc_list_init(psyc_list_ptr, elements_ptr, list.len());
|
||||||
|
buffer = Vec::with_capacity(psyc_list.length);
|
||||||
|
buffer.set_len(psyc_list.length);
|
||||||
|
let buffer_ptr = buffer.as_ptr() as *mut c_char;
|
||||||
|
let _ = psyc_render_list(psyc_list_ptr, buffer_ptr, psyc_list.length);
|
||||||
|
}
|
||||||
|
PsycList {
|
||||||
|
rendered_list: buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a PsycList from a list of strings (comfort function)
|
||||||
|
pub fn from_strings(list: &[&str]) -> Self {
|
||||||
|
let list_slices: Vec<&[u8]> = list.iter().map(|e| e.as_bytes()).collect();
|
||||||
|
Self::new(&list_slices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PsycDict {
|
||||||
|
/// Construct a PsycDict from a list of key value pairs
|
||||||
|
pub fn new(dict: &[(&[u8], &[u8])]) -> Self {
|
||||||
|
let mut psyc_dict: RawPsycDict;
|
||||||
|
let elements: Vec<PsycDictElem>;
|
||||||
|
let mut buffer: Vec<u8>;
|
||||||
|
unsafe {
|
||||||
|
psyc_dict = mem::uninitialized();
|
||||||
|
let psyc_dict_ptr = &mut psyc_dict as *mut RawPsycDict;
|
||||||
|
elements = dict.iter().map(|e| make_psyc_dict_elem(e)).collect();
|
||||||
|
let elements_ptr = elements.as_ptr() as *const PsycDictElem;
|
||||||
|
psyc_dict_init(psyc_dict_ptr, elements_ptr, dict.len());
|
||||||
|
buffer = Vec::with_capacity(psyc_dict.length);
|
||||||
|
buffer.set_len(psyc_dict.length);
|
||||||
|
let buffer_ptr = buffer.as_ptr() as *mut c_char;
|
||||||
|
let _ = psyc_render_dict(psyc_dict_ptr, buffer_ptr, psyc_dict.length);
|
||||||
|
}
|
||||||
|
PsycDict{
|
||||||
|
rendered_dict: buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a PsycDict from a list of key / value string pairs (comfort
|
||||||
|
/// function)
|
||||||
|
pub fn from_strings(dict: &[(&str, &str)]) -> Self {
|
||||||
|
let kv_list_slices: Vec<(&[u8], &[u8])> = dict.iter().map(|e| {
|
||||||
|
let &(k, v) = e;
|
||||||
|
(k.as_bytes(), v.as_bytes())
|
||||||
|
}).collect();
|
||||||
|
Self::new(&kv_list_slices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PsycModifier<'a> {
|
||||||
|
/// construct a PsycModifier
|
||||||
|
pub fn new(operator: PsycOperator, name: &'a str, value: &'a [u8]) -> Self {
|
||||||
|
PsycModifier {name: name, value: value, operator: operator}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// construct a PsycModifier with string value (comfort function)
|
||||||
|
pub fn with_string_value(operator: PsycOperator,
|
||||||
|
name: &'a str,
|
||||||
|
value: &'a str)
|
||||||
|
-> Self {
|
||||||
|
PsycModifier {
|
||||||
|
name: name,
|
||||||
|
value: value.as_bytes(),
|
||||||
|
operator: operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// construct a PsycModifier with list value
|
||||||
|
pub fn with_list_value(operator: PsycOperator,
|
||||||
|
name: &'a str,
|
||||||
|
value: &'a PsycList)
|
||||||
|
-> Self {
|
||||||
|
PsycModifier {
|
||||||
|
name: name,
|
||||||
|
value: &value.rendered_list,
|
||||||
|
operator: operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// construct a PsycModifier with a dictionary value (comfort function)
|
||||||
|
pub fn with_dict_value(operator: PsycOperator,
|
||||||
|
name: &'a str,
|
||||||
|
value: &'a PsycDict)
|
||||||
|
-> Self {
|
||||||
|
PsycModifier {
|
||||||
|
name: name,
|
||||||
|
value: &value.rendered_dict,
|
||||||
|
operator: operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PsycPacket<'a> {
|
||||||
|
///
|
||||||
|
pub fn new(routing_modifiers: &'a [PsycModifier],
|
||||||
|
entity_modifiers: &'a [PsycModifier],
|
||||||
|
method: &'a str,
|
||||||
|
data: &'a [u8],
|
||||||
|
state_operator: PsycStateOp)
|
||||||
|
-> Self {
|
||||||
|
let mut packet: RawPsycPacket;
|
||||||
|
let raw_routing_modifiers: Vec<RawPsycModifier>;
|
||||||
|
let raw_entity_modifiers: Vec<RawPsycModifier>;
|
||||||
|
unsafe{
|
||||||
|
packet = mem::uninitialized();
|
||||||
|
let packet_ptr = &mut packet as *mut RawPsycPacket;
|
||||||
|
raw_routing_modifiers = routing_modifiers.iter().map(
|
||||||
|
|m| Self::make_raw_modifier(m, PsycModifierFlag::PSYC_MODIFIER_ROUTING)
|
||||||
|
).collect();
|
||||||
|
raw_entity_modifiers = entity_modifiers.iter().map(
|
||||||
|
|m| Self::make_raw_modifier(m, PsycModifierFlag::PSYC_MODIFIER_CHECK_LENGTH)
|
||||||
|
).collect();
|
||||||
|
psyc_packet_init(packet_ptr,
|
||||||
|
raw_routing_modifiers.as_ptr() as *const RawPsycModifier,
|
||||||
|
raw_routing_modifiers.len(),
|
||||||
|
raw_entity_modifiers.as_ptr() as *const RawPsycModifier,
|
||||||
|
raw_entity_modifiers.len(),
|
||||||
|
method.as_ptr() as *const c_char,
|
||||||
|
method.len(),
|
||||||
|
data.as_ptr() as *const c_char,
|
||||||
|
data.len(),
|
||||||
|
state_operator as c_char,
|
||||||
|
PsycPacketFlag::PSYC_PACKET_CHECK_LENGTH);
|
||||||
|
}
|
||||||
|
PsycPacket {
|
||||||
|
raw_packet: packet,
|
||||||
|
routing_modifiers: routing_modifiers,
|
||||||
|
entity_modifiers: entity_modifiers,
|
||||||
|
raw_routing_modifiers: raw_routing_modifiers,
|
||||||
|
raw_entity_modifiers: raw_entity_modifiers,
|
||||||
|
method: method,
|
||||||
|
body: data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_raw(routing_modifiers: &'a [PsycModifier],
|
||||||
|
content: &'a [u8]) -> Self {
|
||||||
|
let mut packet: RawPsycPacket;
|
||||||
|
let raw_routing_modifiers: Vec<RawPsycModifier>;
|
||||||
|
unsafe {
|
||||||
|
packet = mem::uninitialized();
|
||||||
|
let packet_ptr = &mut packet as *mut RawPsycPacket;
|
||||||
|
raw_routing_modifiers = routing_modifiers.iter().map(
|
||||||
|
|m| Self::make_raw_modifier(m, PsycModifierFlag::PSYC_MODIFIER_ROUTING)
|
||||||
|
).collect();
|
||||||
|
psyc_packet_init_raw(packet_ptr,
|
||||||
|
raw_routing_modifiers.as_ptr() as *const RawPsycModifier,
|
||||||
|
raw_routing_modifiers.len(),
|
||||||
|
content.as_ptr() as *const c_char,
|
||||||
|
content.len(),
|
||||||
|
PsycPacketFlag::PSYC_PACKET_CHECK_LENGTH);
|
||||||
|
}
|
||||||
|
PsycPacket {
|
||||||
|
raw_packet: packet,
|
||||||
|
routing_modifiers: routing_modifiers,
|
||||||
|
entity_modifiers: &[],
|
||||||
|
raw_routing_modifiers: raw_routing_modifiers,
|
||||||
|
raw_entity_modifiers: vec![],
|
||||||
|
method: "",
|
||||||
|
body: content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the length of the rendered packet
|
||||||
|
pub fn length(&self) -> usize {
|
||||||
|
self.raw_packet.length
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn render(&self) -> Result<Vec<u8>, PsycRenderError> {
|
||||||
|
let raw_packet_ptr = & self.raw_packet as *const RawPsycPacket;
|
||||||
|
let mut buffer = Vec::with_capacity(self.length());
|
||||||
|
let buffer_ptr = buffer.as_mut_ptr() as *mut c_char;
|
||||||
|
unsafe {
|
||||||
|
buffer.set_len(self.length());
|
||||||
|
let result = psyc_render(raw_packet_ptr, buffer_ptr, buffer.capacity());
|
||||||
|
match result {
|
||||||
|
PsycRenderRC::PSYC_RENDER_SUCCESS => Ok(buffer),
|
||||||
|
_error => Err(mem::transmute(_error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_raw_modifier(modifier: &'a PsycModifier,
|
||||||
|
flag: PsycModifierFlag)
|
||||||
|
-> RawPsycModifier {
|
||||||
|
let mut raw_modifier: RawPsycModifier;
|
||||||
|
unsafe {
|
||||||
|
raw_modifier = mem::uninitialized();
|
||||||
|
let raw_modifier_ptr = &mut raw_modifier as *mut RawPsycModifier;
|
||||||
|
let name_ptr = modifier.name.as_ptr() as *const c_char;
|
||||||
|
let value_ptr = modifier.value.as_ptr() as *const c_char;
|
||||||
|
psyc_modifier_init(raw_modifier_ptr,
|
||||||
|
modifier.operator,
|
||||||
|
name_ptr,
|
||||||
|
modifier.name.len(),
|
||||||
|
value_ptr,
|
||||||
|
modifier.value.len(),
|
||||||
|
flag);
|
||||||
|
}
|
||||||
|
raw_modifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn make_psyc_elem(list_element: &[u8]) -> PsycElem {
|
||||||
|
let list_element_ptr = list_element.as_ptr() as *const c_char;
|
||||||
|
PsycElem {
|
||||||
|
elem_type: PsycString {length: 0, data: ptr::null()},
|
||||||
|
value: PsycString {length: list_element.len(), data: list_element_ptr},
|
||||||
|
length: 0,
|
||||||
|
flag: PsycElemFlag::PSYC_ELEM_CHECK_LENGTH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn make_psyc_dict_elem(dict_element: &(&[u8], &[u8])) -> PsycDictElem {
|
||||||
|
let &(key, value) = dict_element;
|
||||||
|
let key_ptr = key.as_ptr() as *const c_char;
|
||||||
|
let psyc_dict_elem_value = make_psyc_elem(value);
|
||||||
|
let psyc_dict_elem_key = PsycDictKey {
|
||||||
|
value: PsycString {
|
||||||
|
length: key.len(),
|
||||||
|
data: key_ptr
|
||||||
|
},
|
||||||
|
length: 0,
|
||||||
|
flag: PsycElemFlag::PSYC_ELEM_CHECK_LENGTH
|
||||||
|
};
|
||||||
|
PsycDictElem {
|
||||||
|
value: psyc_dict_elem_value,
|
||||||
|
key: psyc_dict_elem_key
|
||||||
|
}
|
||||||
|
}
|
142
rust/src/packet_types.rs
Normal file
142
rust/src/packet_types.rs
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
use types::*;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycModifierFlag {
|
||||||
|
/// Modifier needs to be checked if it needs length.
|
||||||
|
PSYC_MODIFIER_CHECK_LENGTH = 0,
|
||||||
|
/// Modifier needs length.
|
||||||
|
PSYC_MODIFIER_NEED_LENGTH = 1,
|
||||||
|
/// Modifier doesn't need length.
|
||||||
|
PSYC_MODIFIER_NO_LENGTH = 2,
|
||||||
|
/// Routing modifier, which implies that it doesn't need length.
|
||||||
|
PSYC_MODIFIER_ROUTING = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycElemFlag {
|
||||||
|
/// Element needs to be checked if it needs length.
|
||||||
|
PSYC_ELEM_CHECK_LENGTH = 0,
|
||||||
|
/// Element needs length.
|
||||||
|
PSYC_ELEM_NEED_LENGTH = 1,
|
||||||
|
/// Element doesn't need length.
|
||||||
|
PSYC_ELEM_NO_LENGTH = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycPacketFlag {
|
||||||
|
/// Packet needs to be checked if it needs content length.
|
||||||
|
PSYC_PACKET_CHECK_LENGTH = 0,
|
||||||
|
/// Packet needs content length.
|
||||||
|
PSYC_PACKET_NEED_LENGTH = 1,
|
||||||
|
/// Packet doesn't need content length.
|
||||||
|
PSYC_PACKET_NO_LENGTH = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycOperator {
|
||||||
|
PSYC_OPERATOR_SET = ':' as _,
|
||||||
|
PSYC_OPERATOR_ASSIGN = '=' as _,
|
||||||
|
PSYC_OPERATOR_AUGMENT = '+' as _,
|
||||||
|
PSYC_OPERATOR_DIMINISH = '-' as _,
|
||||||
|
PSYC_OPERATOR_UPDATE = '@' as _,
|
||||||
|
PSYC_OPERATOR_QUERY = '?' as _,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycStateOp {
|
||||||
|
PSYC_STATE_NOOP = 0,
|
||||||
|
PSYC_STATE_RESET = '=' as _,
|
||||||
|
PSYC_STATE_RESYNC = '?' as _,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycPacketId {
|
||||||
|
PSYC_PACKET_ID_CONTEXT = 0,
|
||||||
|
PSYC_PACKET_ID_SOURCE = 1,
|
||||||
|
PSYC_PACKET_ID_TARGET = 2,
|
||||||
|
PSYC_PACKET_ID_COUNTER = 3,
|
||||||
|
PSYC_PACKET_ID_FRAGMENT = 4,
|
||||||
|
PSYC_PACKET_ID_ELEMS = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycElem {
|
||||||
|
pub elem_type: PsycString,
|
||||||
|
pub value: PsycString,
|
||||||
|
pub length: usize,
|
||||||
|
pub flag: PsycElemFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycDictKey {
|
||||||
|
pub value: PsycString,
|
||||||
|
pub length: usize,
|
||||||
|
pub flag: PsycElemFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycDictElem {
|
||||||
|
pub value: PsycElem,
|
||||||
|
pub key: PsycDictKey
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RawPsycDict {
|
||||||
|
dict_type: PsycString,
|
||||||
|
elems: *const PsycDictElem,
|
||||||
|
num_elems: usize,
|
||||||
|
pub length: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RawPsycList {
|
||||||
|
list_type: PsycString,
|
||||||
|
elems: *const PsycElem,
|
||||||
|
num_elems: usize,
|
||||||
|
pub length: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RawPsycModifier {
|
||||||
|
name: PsycString,
|
||||||
|
value: PsycString,
|
||||||
|
flag: PsycModifierFlag,
|
||||||
|
oper: c_char
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycHeader {
|
||||||
|
lines: usize,
|
||||||
|
modifiers: *mut RawPsycModifier
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RawPsycPacket {
|
||||||
|
routing: PsycHeader,
|
||||||
|
entity: PsycHeader,
|
||||||
|
method: PsycString,
|
||||||
|
data: PsycString,
|
||||||
|
content: PsycString,
|
||||||
|
routinglen: usize,
|
||||||
|
contentlen: usize,
|
||||||
|
pub length: usize,
|
||||||
|
stateop: PsycStateOp,
|
||||||
|
flag: PsycPacketFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycRenderRC {
|
||||||
|
/// Error, method is missing, but data is present.
|
||||||
|
PSYC_RENDER_ERROR_METHOD_MISSING = -3,
|
||||||
|
/// Error, a modifier name is missing.
|
||||||
|
PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING = -2,
|
||||||
|
/// Error, buffer is too small to render the packet.
|
||||||
|
PSYC_RENDER_ERROR = -1,
|
||||||
|
/// Packet is rendered successfully in the buffer.
|
||||||
|
PSYC_RENDER_SUCCESS = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
254
rust/src/parser.rs
Normal file
254
rust/src/parser.rs
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
use types::*;
|
||||||
|
use parser_types::*;
|
||||||
|
use std::mem;
|
||||||
|
use std::slice;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn psyc_parse_state_init(state: *mut PsycParseState, flags: u8);
|
||||||
|
fn psyc_parse_buffer_set(state: *mut PsycParseState, buffer: *const c_char, length: usize);
|
||||||
|
fn psyc_parse_list_state_init(state: *mut PsycParseState);
|
||||||
|
fn psyc_parse_list_buffer_set(state: *mut PsycParseState, buffer: *const c_char, length: usize);
|
||||||
|
fn psyc_parse_dict_state_init(state: *mut PsycParseState);
|
||||||
|
fn psyc_parse_dict_buffer_set(state: *mut PsycParseState, buffer: *const c_char, length: usize);
|
||||||
|
fn psyc_parse_index_state_init(state: *mut PsycParseState);
|
||||||
|
fn psyc_parse_index_buffer_set(state: *mut PsycParseState, buffer: *const c_char, length: usize);
|
||||||
|
fn psyc_parse_update_state_init(state: *mut PsycParseState);
|
||||||
|
fn psyc_parse_update_buffer_set(state: *mut PsycParseState, buffer: *const c_char, length: usize);
|
||||||
|
fn psyc_parse_content_length(state: *mut PsycParseState) -> usize;
|
||||||
|
fn psyc_parse_content_length_found(state: *mut PsycParseState) -> bool;
|
||||||
|
fn psyc_parse_value_length(state: *mut PsycParseState) -> usize;
|
||||||
|
fn psyc_parse_value_length_found(state: *mut PsycParseState) -> bool;
|
||||||
|
fn psyc_parse_cursor(state: *mut PsycParseState) -> usize;
|
||||||
|
fn psyc_parse_buffer_length(state: *mut PsycParseState) -> usize;
|
||||||
|
fn psyc_parse_remaining_length(state: *mut PsycParseState) -> usize;
|
||||||
|
fn psyc_parse_remaining_buffer(state: *mut PsycParseState) -> *const c_char;
|
||||||
|
fn psyc_parse(state: *mut PsycParseState,
|
||||||
|
oper: *mut c_char,
|
||||||
|
name: *mut PsycString,
|
||||||
|
value: *mut PsycString)
|
||||||
|
-> PsycParseRC;
|
||||||
|
|
||||||
|
fn psyc_parse_list(state: *mut PsycParseListState,
|
||||||
|
list_type: *mut PsycString,
|
||||||
|
elem: *mut PsycString)
|
||||||
|
-> PsycParseListRC;
|
||||||
|
|
||||||
|
fn psyc_parse_dict(state: *mut PsycParseDictState,
|
||||||
|
dict_type: *mut PsycString,
|
||||||
|
elem: *mut PsycString)
|
||||||
|
-> PsycParseDictRC;
|
||||||
|
|
||||||
|
fn psyc_parse_index(state: *mut PsycParseIndexState,
|
||||||
|
idx: *mut PsycString)
|
||||||
|
-> PsycParseIndexRC;
|
||||||
|
|
||||||
|
fn psyc_parse_update(state: *mut PsycParseUpdateState,
|
||||||
|
oper: *mut c_char,
|
||||||
|
value: *mut PsycString)
|
||||||
|
-> PsycParseUpdateRC;
|
||||||
|
|
||||||
|
fn psyc_parse_uint(value: *const c_char, len: usize, n: *mut u64) -> usize;
|
||||||
|
fn psyc_parse_list_index(value: *const c_char, len: usize, n: *mut i64) -> usize;
|
||||||
|
fn psyc_is_oper(g: c_char) -> bool;
|
||||||
|
fn psyc_is_numeric(c: c_char) -> bool;
|
||||||
|
fn psyc_is_alpha(c: c_char) -> bool;
|
||||||
|
fn psyc_is_alpha_numeric(c: c_char) -> bool;
|
||||||
|
fn psyc_is_kw_char(c: c_char) -> bool;
|
||||||
|
fn psyc_is_name_char(c: c_char) -> bool;
|
||||||
|
fn psyc_is_host_char(c: c_char) -> bool;
|
||||||
|
fn psyc_parse_keyword(data: *const c_char, len: usize) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycParser {
|
||||||
|
state: PsycParseState
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycListParser {
|
||||||
|
state: PsycParseListState
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycDictParser {
|
||||||
|
state: PsycParseDictState
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycIndexParser {
|
||||||
|
state: PsycParseIndexState
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PsycUpdateParser {
|
||||||
|
state: PsycParseUpdateState
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum PsycParserResult {
|
||||||
|
StateSync,
|
||||||
|
StateReset,
|
||||||
|
ParsingComplete,
|
||||||
|
RoutingModifier {
|
||||||
|
operator: char,
|
||||||
|
name: String,
|
||||||
|
value: Vec<u8>
|
||||||
|
},
|
||||||
|
EntityModifier {
|
||||||
|
operator: char,
|
||||||
|
name: String,
|
||||||
|
value: Vec<u8>
|
||||||
|
},
|
||||||
|
IncompleteEntityModifier {
|
||||||
|
operator: char,
|
||||||
|
name: String,
|
||||||
|
value: Vec<u8>,
|
||||||
|
cursor: usize
|
||||||
|
},
|
||||||
|
Body {
|
||||||
|
name: String,
|
||||||
|
value: Vec<u8>
|
||||||
|
},
|
||||||
|
IncompleteBody {
|
||||||
|
name: String,
|
||||||
|
value: Vec<u8>,
|
||||||
|
cursor: usize
|
||||||
|
},
|
||||||
|
InsufficientData {
|
||||||
|
cursor: usize
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum PsycParserError {
|
||||||
|
NoModifierLength = PsycParseRC::PSYC_PARSE_ERROR_MOD_NO_LEN as _,
|
||||||
|
NoContentLength = PsycParseRC::PSYC_PARSE_ERROR_NO_LEN as _,
|
||||||
|
NoEndDelimiter = PsycParseRC::PSYC_PARSE_ERROR_END as _,
|
||||||
|
NoNewlineAfterMethod = PsycParseRC::PSYC_PARSE_ERROR_METHOD as _,
|
||||||
|
NoNewlineAfterModifier = PsycParseRC::PSYC_PARSE_ERROR_MOD_NL as _,
|
||||||
|
InvalidModifierLength = PsycParseRC::PSYC_PARSE_ERROR_MOD_LEN as _,
|
||||||
|
NoTabBeforeModifierValue = PsycParseRC::PSYC_PARSE_ERROR_MOD_TAB as _,
|
||||||
|
NoModifierName = PsycParseRC::PSYC_PARSE_ERROR_MOD_NAME as _,
|
||||||
|
NoNewlineAfterContentLength = PsycParseRC::PSYC_PARSE_ERROR_LENGTH as _,
|
||||||
|
GenericError = PsycParseRC::PSYC_PARSE_ERROR as _,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PsycParser {
|
||||||
|
/// Create a PsycParser
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut state: PsycParseState;
|
||||||
|
unsafe {
|
||||||
|
state = mem::uninitialized();
|
||||||
|
let state_ptr = &mut state as *mut PsycParseState;
|
||||||
|
psyc_parse_state_init(state_ptr, PsycParseFlag::PSYC_PARSE_ALL as u8)
|
||||||
|
}
|
||||||
|
PsycParser{state: state}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a buffer of raw bytes for parsing
|
||||||
|
pub fn set_buffer(&mut self, buffer: &[u8]) {
|
||||||
|
let state_ptr = &mut self.state as *mut PsycParseState;
|
||||||
|
let buffer_ptr = &buffer[0] as *const u8 as *const c_char;
|
||||||
|
unsafe {
|
||||||
|
psyc_parse_buffer_set(state_ptr, buffer_ptr, buffer.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the buffer previously set by set_buffer. Call repeatedly until the
|
||||||
|
/// result is PsycParserResult::ParsingComplete or a PsycParserError.
|
||||||
|
pub fn parse(&mut self) -> Result<PsycParserResult, PsycParserError> {
|
||||||
|
let state_ptr = &mut self.state as *mut PsycParseState;
|
||||||
|
let mut operator: char;
|
||||||
|
let mut name: PsycString;
|
||||||
|
let mut value: PsycString;
|
||||||
|
unsafe {
|
||||||
|
operator = mem::uninitialized();
|
||||||
|
name = mem::uninitialized();
|
||||||
|
value = mem::uninitialized();
|
||||||
|
let operator_ptr = &mut operator as *mut char as *mut c_char;
|
||||||
|
let name_ptr = &mut name as *mut PsycString;
|
||||||
|
let value_ptr = &mut value as *mut PsycString;
|
||||||
|
let parse_result = psyc_parse(state_ptr, operator_ptr, name_ptr, value_ptr);
|
||||||
|
match parse_result {
|
||||||
|
PsycParseRC::PSYC_PARSE_INSUFFICIENT => {
|
||||||
|
let result =
|
||||||
|
PsycParserResult::InsufficientData {
|
||||||
|
cursor: psyc_parse_cursor(state_ptr)
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_ROUTING => {
|
||||||
|
let result =
|
||||||
|
PsycParserResult::RoutingModifier {
|
||||||
|
operator: operator,
|
||||||
|
name: Self::cstring_to_string(name.data, name.length),
|
||||||
|
value: Self::cstring_to_bytes(value.data, value.length)
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_ENTITY |
|
||||||
|
PsycParseRC::PSYC_PARSE_ENTITY_END => {
|
||||||
|
let result =
|
||||||
|
PsycParserResult::EntityModifier {
|
||||||
|
operator: operator,
|
||||||
|
name: Self::cstring_to_string(name.data, name.length),
|
||||||
|
value: Self::cstring_to_bytes(value.data, value.length)
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_ENTITY_START |
|
||||||
|
PsycParseRC::PSYC_PARSE_ENTITY_CONT => {
|
||||||
|
let result =
|
||||||
|
PsycParserResult::IncompleteEntityModifier {
|
||||||
|
operator: operator,
|
||||||
|
name: Self::cstring_to_string(name.data, name.length),
|
||||||
|
value: Self::cstring_to_bytes(value.data, value.length),
|
||||||
|
cursor: psyc_parse_cursor(state_ptr)
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_BODY |
|
||||||
|
PsycParseRC::PSYC_PARSE_BODY_END => {
|
||||||
|
let result =
|
||||||
|
PsycParserResult::Body {
|
||||||
|
name: Self::cstring_to_string(name.data, name.length),
|
||||||
|
value: Self::cstring_to_bytes(value.data, value.length)
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_BODY_START |
|
||||||
|
PsycParseRC::PSYC_PARSE_BODY_CONT => {
|
||||||
|
let result =
|
||||||
|
PsycParserResult::IncompleteBody {
|
||||||
|
name: Self::cstring_to_string(name.data, name.length),
|
||||||
|
value: Self::cstring_to_bytes(value.data, value.length),
|
||||||
|
cursor: psyc_parse_cursor(state_ptr)
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_STATE_RESYNC =>
|
||||||
|
Ok(PsycParserResult::StateSync),
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_STATE_RESET =>
|
||||||
|
Ok(PsycParserResult::StateReset),
|
||||||
|
|
||||||
|
PsycParseRC::PSYC_PARSE_COMPLETE =>
|
||||||
|
Ok(PsycParserResult::ParsingComplete),
|
||||||
|
|
||||||
|
_error => Err(mem::transmute(_error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn cstring_to_string(cstring: *const c_char, length: usize) -> String {
|
||||||
|
let vec = Self::cstring_to_bytes(cstring, length);
|
||||||
|
String::from_utf8(vec).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn cstring_to_bytes(cstring: *const c_char, length: usize) -> Vec<u8> {
|
||||||
|
slice::from_raw_parts(cstring as *const u8, length).to_vec()
|
||||||
|
}
|
||||||
|
}
|
300
rust/src/parser_types.rs
Normal file
300
rust/src/parser_types.rs
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
use types::*;
|
||||||
|
|
||||||
|
enum PsycPart { }
|
||||||
|
enum PsycListPart { }
|
||||||
|
enum PsycDictPart { }
|
||||||
|
enum PsycIndexPart { }
|
||||||
|
enum PsycUpdatePart { }
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycParseState {
|
||||||
|
buffer: PsycString,
|
||||||
|
cursor: usize,
|
||||||
|
startc: usize,
|
||||||
|
routinglen: usize,
|
||||||
|
contentlen: usize,
|
||||||
|
content_parsed: usize,
|
||||||
|
valuelen: usize,
|
||||||
|
value_parsed: usize,
|
||||||
|
part: PsycPart,
|
||||||
|
flags: u8,
|
||||||
|
contentlen_found: u8,
|
||||||
|
valuelen_found: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycParseListState {
|
||||||
|
buffer: PsycString,
|
||||||
|
cursor: usize,
|
||||||
|
startc: usize,
|
||||||
|
list_type: PsycString,
|
||||||
|
elemlen: usize,
|
||||||
|
elem_parsed: usize,
|
||||||
|
part: PsycListPart,
|
||||||
|
elemlen_found: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycParseDictState {
|
||||||
|
buffer: PsycString,
|
||||||
|
cursor: usize,
|
||||||
|
startc: usize,
|
||||||
|
elemlen: usize,
|
||||||
|
elem_parsed: usize,
|
||||||
|
part: PsycDictPart,
|
||||||
|
elemlen_found: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycParseIndexState {
|
||||||
|
buffer: PsycString,
|
||||||
|
cursor: usize,
|
||||||
|
startc: usize,
|
||||||
|
elemlen: usize,
|
||||||
|
elem_parsed: usize,
|
||||||
|
part: PsycIndexPart,
|
||||||
|
elemlen_found: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycParseUpdateState {
|
||||||
|
buffer: PsycString,
|
||||||
|
cursor: usize,
|
||||||
|
startc: usize,
|
||||||
|
elemlen: usize,
|
||||||
|
elem_parsed: usize,
|
||||||
|
part: PsycUpdatePart,
|
||||||
|
elemlen_found: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycParseFlag {
|
||||||
|
/// Default Flag. Parse everything.
|
||||||
|
PSYC_PARSE_ALL = 0,
|
||||||
|
/// Parse only the header
|
||||||
|
PSYC_PARSE_ROUTING_ONLY = 1,
|
||||||
|
/// Parse only the content.
|
||||||
|
/// Parsing starts at the content and the content must be complete.
|
||||||
|
PSYC_PARSE_START_AT_CONTENT = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycParseRC {
|
||||||
|
/// Error, no length is set for a modifier which is longer than PSYC_MODIFIER_SIZE_THRESHOLD.
|
||||||
|
PSYC_PARSE_ERROR_MOD_NO_LEN = -10,
|
||||||
|
/// Error, no length is set for the content but it is longer than PSYC_CONTENT_SIZE_THRESHOLD.
|
||||||
|
PSYC_PARSE_ERROR_NO_LEN = -9,
|
||||||
|
/// Error, packet is not ending with a valid delimiter.
|
||||||
|
PSYC_PARSE_ERROR_END = -8,
|
||||||
|
/// Error, expected NL after the method.
|
||||||
|
PSYC_PARSE_ERROR_METHOD = -7,
|
||||||
|
/// Error, expected NL after a modifier.
|
||||||
|
PSYC_PARSE_ERROR_MOD_NL = -6,
|
||||||
|
/// Error, modifier length is not numeric.
|
||||||
|
PSYC_PARSE_ERROR_MOD_LEN = -5,
|
||||||
|
/// Error, expected TAB before modifier value.
|
||||||
|
PSYC_PARSE_ERROR_MOD_TAB = -4,
|
||||||
|
/// Error, modifier name is missing.
|
||||||
|
PSYC_PARSE_ERROR_MOD_NAME = -3,
|
||||||
|
/// Error, expected NL after the content length.
|
||||||
|
PSYC_PARSE_ERROR_LENGTH = -2,
|
||||||
|
/// Error in packet.
|
||||||
|
PSYC_PARSE_ERROR = -1,
|
||||||
|
/// Buffer contains insufficient amount of data.
|
||||||
|
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||||
|
/// from the cursor position to the end.
|
||||||
|
PSYC_PARSE_INSUFFICIENT = 1,
|
||||||
|
/// Routing modifier parsing done.
|
||||||
|
/// Operator, name & value contains the respective parts.
|
||||||
|
PSYC_PARSE_ROUTING = 2,
|
||||||
|
/// State sync operation.
|
||||||
|
PSYC_PARSE_STATE_RESYNC = 3,
|
||||||
|
/// State reset operation.
|
||||||
|
PSYC_PARSE_STATE_RESET = 4,
|
||||||
|
/// Start of an incomplete entity modifier.
|
||||||
|
/// Operator & name are complete, value is incomplete.
|
||||||
|
PSYC_PARSE_ENTITY_START = 5,
|
||||||
|
/// Continuation of an incomplete entity modifier.
|
||||||
|
PSYC_PARSE_ENTITY_CONT = 6,
|
||||||
|
/// End of an incomplete entity modifier.
|
||||||
|
PSYC_PARSE_ENTITY_END = 7,
|
||||||
|
/// Entity modifier parsing done in one go.
|
||||||
|
/// Operator, name & value contains the respective parts.
|
||||||
|
PSYC_PARSE_ENTITY = 8,
|
||||||
|
/// Start of an incomplete body.
|
||||||
|
/// Name contains method, value contains part of the body.
|
||||||
|
/// Used when packet length is given
|
||||||
|
PSYC_PARSE_BODY_START = 9,
|
||||||
|
/// Continuation of an incomplete body.
|
||||||
|
/// Used when packet length is given
|
||||||
|
PSYC_PARSE_BODY_CONT = 10,
|
||||||
|
/// End of an incomplete body.
|
||||||
|
/// Used when packet length is given
|
||||||
|
PSYC_PARSE_BODY_END = 11,
|
||||||
|
/// Body parsing done in one go, name contains method, value contains body.
|
||||||
|
PSYC_PARSE_BODY = 12,
|
||||||
|
///// Start of an incomplete content, value contains part of content.
|
||||||
|
///// Used when PSYC_PARSE_ROUTING_ONLY is set.
|
||||||
|
//PSYC_PARSE_CONTENT_START = 9,
|
||||||
|
///// Continuation of an incomplete content.
|
||||||
|
///// Used when PSYC_PARSE_ROUTING_ONLY is set.
|
||||||
|
//PSYC_PARSE_CONTENT_CONT = 10,
|
||||||
|
///// End of an incomplete content.
|
||||||
|
///// Used when PSYC_PARSE_ROUTING_ONLY is set.
|
||||||
|
//PSYC_PARSE_CONTENT_END = 11,
|
||||||
|
///// Content parsing done in one go, value contains the whole content.
|
||||||
|
///// Used when PSYC_PARSE_ROUTING_ONLY is set.
|
||||||
|
//PSYC_PARSE_CONTENT = 12,
|
||||||
|
/// Finished parsing packet.
|
||||||
|
PSYC_PARSE_COMPLETE = 13,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycParseListRC {
|
||||||
|
/// Error, no length is set for an element which is longer than PSYC_ELEM_SIZE_THRESHOLD.
|
||||||
|
PSYC_PARSE_LIST_ERROR_ELEM_NO_LEN = -6,
|
||||||
|
PSYC_PARSE_LIST_ERROR_ELEM_LENGTH = -5,
|
||||||
|
PSYC_PARSE_LIST_ERROR_ELEM_TYPE = -4,
|
||||||
|
PSYC_PARSE_LIST_ERROR_ELEM_START = -3,
|
||||||
|
PSYC_PARSE_LIST_ERROR_TYPE = -2,
|
||||||
|
PSYC_PARSE_LIST_ERROR = -1,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
/// Buffer contains insufficient amount of data.
|
||||||
|
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||||
|
/// from the cursor position to the end.
|
||||||
|
PSYC_PARSE_LIST_INSUFFICIENT = 1,
|
||||||
|
/// Completed parsing the default type of the list.
|
||||||
|
PSYC_PARSE_LIST_TYPE = 2,
|
||||||
|
/// Start of an element is parsed but still not complete.
|
||||||
|
PSYC_PARSE_LIST_ELEM_START = 3,
|
||||||
|
/// Continuation of an incomplete element.
|
||||||
|
PSYC_PARSE_LIST_ELEM_CONT = 4,
|
||||||
|
/// Element parsing completed.
|
||||||
|
PSYC_PARSE_LIST_ELEM_END = 5,
|
||||||
|
/// Completed parsing a list element.
|
||||||
|
PSYC_PARSE_LIST_ELEM = 6,
|
||||||
|
/// Completed parsing the last element in the list.
|
||||||
|
PSYC_PARSE_LIST_ELEM_LAST = 7,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
PSYC_PARSE_LIST_END = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycParseDictRC {
|
||||||
|
PSYC_PARSE_DICT_ERROR_VALUE = -9,
|
||||||
|
PSYC_PARSE_DICT_ERROR_VALUE_LENGTH = -8,
|
||||||
|
PSYC_PARSE_DICT_ERROR_VALUE_TYPE = -7,
|
||||||
|
PSYC_PARSE_DICT_ERROR_VALUE_START = -6,
|
||||||
|
PSYC_PARSE_DICT_ERROR_KEY = -5,
|
||||||
|
PSYC_PARSE_DICT_ERROR_KEY_LENGTH = -4,
|
||||||
|
PSYC_PARSE_DICT_ERROR_KEY_START = -3,
|
||||||
|
PSYC_PARSE_DICT_ERROR_TYPE = -2,
|
||||||
|
PSYC_PARSE_DICT_ERROR = -1,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
/// Buffer contains insufficient amount of data.
|
||||||
|
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||||
|
/// from the cursor position to the end.
|
||||||
|
PSYC_PARSE_DICT_INSUFFICIENT = 1,
|
||||||
|
/// Completed parsing the default type of the dict.
|
||||||
|
PSYC_PARSE_DICT_TYPE = 2,
|
||||||
|
/// Start of a key is parsed but still not complete.
|
||||||
|
PSYC_PARSE_DICT_KEY_START = 3,
|
||||||
|
/// Continuation of an incomplete key.
|
||||||
|
PSYC_PARSE_DICT_KEY_CONT = 4,
|
||||||
|
/// Last continuation of a key.
|
||||||
|
PSYC_PARSE_DICT_KEY_END = 5,
|
||||||
|
/// Completed parsing a key in one go.
|
||||||
|
PSYC_PARSE_DICT_KEY = 6,
|
||||||
|
/// Start of a value is parsed but still not complete.
|
||||||
|
PSYC_PARSE_DICT_VALUE_START = 7,
|
||||||
|
/// Continuation of an incomplete value.
|
||||||
|
PSYC_PARSE_DICT_VALUE_CONT = 8,
|
||||||
|
/// Last continuation of a value.
|
||||||
|
PSYC_PARSE_DICT_VALUE_END = 9,
|
||||||
|
/// Completed parsing a value.
|
||||||
|
PSYC_PARSE_DICT_VALUE = 10,
|
||||||
|
/// Completed parsing the last value.
|
||||||
|
PSYC_PARSE_DICT_VALUE_LAST = 11,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
PSYC_PARSE_DICT_END = 12,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycParseIndexRC {
|
||||||
|
PSYC_PARSE_INDEX_ERROR_DICT = -6,
|
||||||
|
PSYC_PARSE_INDEX_ERROR_DICT_LENGTH = -5,
|
||||||
|
PSYC_PARSE_INDEX_ERROR_STRUCT = -4,
|
||||||
|
PSYC_PARSE_INDEX_ERROR_LIST = -3,
|
||||||
|
PSYC_PARSE_INDEX_ERROR_TYPE = -2,
|
||||||
|
PSYC_PARSE_INDEX_ERROR = -1,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
/// Buffer contains insufficient amount of data.
|
||||||
|
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||||
|
/// from the cursor position to the end.
|
||||||
|
PSYC_PARSE_INDEX_INSUFFICIENT = 1,
|
||||||
|
// Completed parsing a list index.
|
||||||
|
PSYC_PARSE_INDEX_LIST = 3,
|
||||||
|
// Completed parsing a list index at the end of the buffer.
|
||||||
|
PSYC_PARSE_INDEX_LIST_LAST = 4,
|
||||||
|
// Completed parsing a struct element name.
|
||||||
|
PSYC_PARSE_INDEX_STRUCT = 5,
|
||||||
|
// Completed parsing a struct element name at the end of the buffer.
|
||||||
|
PSYC_PARSE_INDEX_STRUCT_LAST = 6,
|
||||||
|
/// Start of a dict key is parsed but still not complete.
|
||||||
|
PSYC_PARSE_INDEX_DICT_START = 7,
|
||||||
|
/// Continuation of an incomplete dict key.
|
||||||
|
PSYC_PARSE_INDEX_DICT_CONT = 8,
|
||||||
|
/// Last continuation of a dict key.
|
||||||
|
PSYC_PARSE_INDEX_DICT_END = 9,
|
||||||
|
/// Completed parsing a dict key in one go.
|
||||||
|
PSYC_PARSE_INDEX_DICT = 10,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
PSYC_PARSE_INDEX_END = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PsycParseUpdateRC {
|
||||||
|
PSYC_PARSE_UPDATE_ERROR_VALUE = -24,
|
||||||
|
PSYC_PARSE_UPDATE_ERROR_LENGTH = -23,
|
||||||
|
PSYC_PARSE_UPDATE_ERROR_TYPE = -22,
|
||||||
|
PSYC_PARSE_UPDATE_ERROR_OPER = -21,
|
||||||
|
PSYC_PARSE_UPDATE_ERROR = -1,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
/// Buffer contains insufficient amount of data.
|
||||||
|
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||||
|
/// from the cursor position to the end.
|
||||||
|
PSYC_PARSE_UPDATE_INSUFFICIENT = 1,
|
||||||
|
|
||||||
|
// Completed parsing a list index.
|
||||||
|
PSYC_PARSE_UPDATE_INDEX_LIST = 3,
|
||||||
|
// Completed parsing a struct element name.
|
||||||
|
PSYC_PARSE_UPDATE_INDEX_STRUCT = 5,
|
||||||
|
/// Start of a dict key is parsed but still not complete.
|
||||||
|
PSYC_PARSE_UPDATE_INDEX_DICT_START = 7,
|
||||||
|
/// Continuation of an incomplete dict key.
|
||||||
|
PSYC_PARSE_UPDATE_INDEX_DICT_CONT = 8,
|
||||||
|
/// Last continuation of a dict key.
|
||||||
|
PSYC_PARSE_UPDATE_INDEX_DICT_END = 9,
|
||||||
|
/// Completed parsing a dict key in one go.
|
||||||
|
PSYC_PARSE_UPDATE_INDEX_DICT = 10,
|
||||||
|
|
||||||
|
/// Completed parsing the type.
|
||||||
|
PSYC_PARSE_UPDATE_TYPE = 21,
|
||||||
|
/// Completed parsing the type and reached end of buffer.
|
||||||
|
PSYC_PARSE_UPDATE_TYPE_END = 22,
|
||||||
|
/// Start of the value is parsed but still not complete.
|
||||||
|
PSYC_PARSE_UPDATE_VALUE_START = 23,
|
||||||
|
/// Continuation of incomplete value.
|
||||||
|
PSYC_PARSE_UPDATE_VALUE_CONT = 24,
|
||||||
|
/// Last continuation of the value.
|
||||||
|
PSYC_PARSE_UPDATE_VALUE_END = 25,
|
||||||
|
/// Completed parsing the value in one go.
|
||||||
|
PSYC_PARSE_UPDATE_VALUE = 26,
|
||||||
|
/// Reached end of buffer.
|
||||||
|
PSYC_PARSE_UPDATE_END = 27,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
9
rust/src/types.rs
Normal file
9
rust/src/types.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PsycString {
|
||||||
|
pub length: usize,
|
||||||
|
pub data: *const c_char
|
||||||
|
}
|
||||||
|
|
||||||
|
|
97
rust/tests/test_packet.rs
Normal file
97
rust/tests/test_packet.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
extern crate psyc;
|
||||||
|
|
||||||
|
use psyc::*;
|
||||||
|
use psyc::packet_types::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_create_render() {
|
||||||
|
let r1 = PsycModifier::new(PsycOperator::PSYC_OPERATOR_SET,
|
||||||
|
"_target",
|
||||||
|
"psyc://ve.symlynx.com/@blog".as_bytes());
|
||||||
|
|
||||||
|
let r2 = PsycModifier::new(PsycOperator::PSYC_OPERATOR_SET,
|
||||||
|
"_tag",
|
||||||
|
"666666".as_bytes());
|
||||||
|
|
||||||
|
let e1 = PsycModifier::new(PsycOperator::PSYC_OPERATOR_SET,
|
||||||
|
"_nick",
|
||||||
|
"lurchi".as_bytes());
|
||||||
|
|
||||||
|
let routing_modifiers = vec![r1, r2];
|
||||||
|
let entity_modifiers = vec![e1];
|
||||||
|
let data = vec![];
|
||||||
|
|
||||||
|
let packet = PsycPacket::new(&routing_modifiers,
|
||||||
|
&entity_modifiers,
|
||||||
|
"_request_context_enter",
|
||||||
|
&data,
|
||||||
|
PsycStateOp::PSYC_STATE_NOOP);
|
||||||
|
|
||||||
|
let expected = ":_target\tpsyc://ve.symlynx.com/@blog\n:_tag\t666666\n\n:_nick\tlurchi\n_request_context_enter\n|\n".as_bytes().to_vec();
|
||||||
|
|
||||||
|
let rendered_packet = packet.render();
|
||||||
|
|
||||||
|
assert_eq!(rendered_packet, Ok(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list() {
|
||||||
|
let r1 = PsycModifier::new(PsycOperator::PSYC_OPERATOR_SET,
|
||||||
|
"_target",
|
||||||
|
"psyc://ve.symlynx.com/@blog".as_bytes());
|
||||||
|
|
||||||
|
let list = PsycList::from_strings(&["str1", "str2", "str3"]);
|
||||||
|
|
||||||
|
let e1 = PsycModifier::with_list_value(PsycOperator::PSYC_OPERATOR_SET,
|
||||||
|
"_list_test",
|
||||||
|
&list);
|
||||||
|
|
||||||
|
let routing_modifiers = vec![r1];
|
||||||
|
let entity_modifiers = vec![e1];
|
||||||
|
let data = vec![];
|
||||||
|
|
||||||
|
let packet = PsycPacket::new(&routing_modifiers,
|
||||||
|
&entity_modifiers,
|
||||||
|
"",
|
||||||
|
&data,
|
||||||
|
PsycStateOp::PSYC_STATE_NOOP);
|
||||||
|
|
||||||
|
let expected = ":_target\tpsyc://ve.symlynx.com/@blog\n34\n:_list_test 18\t| str1| str2| str3\n|\n".as_bytes().to_vec();
|
||||||
|
|
||||||
|
let rendered_packet = packet.render();
|
||||||
|
|
||||||
|
assert_eq!(rendered_packet, Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dict() {
|
||||||
|
let r1 = PsycModifier::new(PsycOperator::PSYC_OPERATOR_SET,
|
||||||
|
"_target",
|
||||||
|
"psyc://ve.symlynx.com/@blog".as_bytes());
|
||||||
|
|
||||||
|
let dict = PsycDict::from_strings(&[("key1", "value1"),
|
||||||
|
("key2", "value2"),
|
||||||
|
("key3", "value3")]);
|
||||||
|
|
||||||
|
let e1 = PsycModifier::with_dict_value(PsycOperator::PSYC_OPERATOR_SET,
|
||||||
|
"_dict_test",
|
||||||
|
&dict);
|
||||||
|
|
||||||
|
let routing_modifiers = vec![r1];
|
||||||
|
let entity_modifiers = vec![e1];
|
||||||
|
let data = vec![];
|
||||||
|
|
||||||
|
let packet = PsycPacket::new(&routing_modifiers,
|
||||||
|
&entity_modifiers,
|
||||||
|
"",
|
||||||
|
&data,
|
||||||
|
PsycStateOp::PSYC_STATE_NOOP);
|
||||||
|
|
||||||
|
let expected = ":_target\tpsyc://ve.symlynx.com/@blog\n58\n:_dict_test 42\t{ key1} value1{ key2} value2{ key3} value3\n|\n".as_bytes().to_vec();
|
||||||
|
|
||||||
|
let rendered_packet = packet.render();
|
||||||
|
|
||||||
|
//println!("rendered: {}", String::from_utf8(rendered_packet.unwrap()).unwrap());
|
||||||
|
|
||||||
|
assert_eq!(rendered_packet, Ok(expected));
|
||||||
|
}
|
26
rust/tests/test_parser.rs
Normal file
26
rust/tests/test_parser.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
extern crate psyc;
|
||||||
|
|
||||||
|
use psyc::parser::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse() {
|
||||||
|
let test_data = ":_target\tpsyc://ve.symlynx.com/@blog\n\n?\n|\n".to_string().into_bytes();
|
||||||
|
|
||||||
|
let expected1 =
|
||||||
|
PsycParserResult::RoutingModifier{
|
||||||
|
operator: ':',
|
||||||
|
name: "_target".to_string(),
|
||||||
|
value: "psyc://ve.symlynx.com/@blog".to_string().into_bytes()
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected2 = PsycParserResult::StateSync;
|
||||||
|
|
||||||
|
let mut parser = PsycParser::new();
|
||||||
|
parser.set_buffer(&test_data);
|
||||||
|
|
||||||
|
let result1 = parser.parse();
|
||||||
|
let result2 = parser.parse();
|
||||||
|
|
||||||
|
assert_eq!(result1, Ok(expected1));
|
||||||
|
assert_eq!(result2, Ok(expected2));
|
||||||
|
}
|
Loading…
Reference in a new issue