mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
added psyctext
This commit is contained in:
parent
4de756b5fd
commit
5d7bdfd7be
5 changed files with 238 additions and 0 deletions
|
@ -6,6 +6,7 @@ mod keyword;
|
|||
mod method_types;
|
||||
mod packet_types;
|
||||
mod parser_types;
|
||||
mod text_types;
|
||||
mod types;
|
||||
mod uniform_types;
|
||||
mod util;
|
||||
|
@ -14,6 +15,7 @@ pub mod method;
|
|||
pub mod parser;
|
||||
pub mod packet;
|
||||
pub mod packet_id;
|
||||
pub mod text;
|
||||
pub mod uniform;
|
||||
pub mod variable;
|
||||
|
||||
|
@ -26,6 +28,8 @@ pub use parser_types::{PsycParserResult, PsycListParserResult, PsycParserError,
|
|||
pub use packet::{PsycList, PsycModifier, PsycPacket};
|
||||
pub use packet_id::PacketId;
|
||||
pub use packet_types::PacketRenderError;
|
||||
pub use text::Text;
|
||||
pub use text_types::SubstitutionResult;
|
||||
pub use uniform::Uniform;
|
||||
pub use uniform_types::{UniformParseError, PsycScheme, PsycEntity};
|
||||
pub use packet_types::{PsycOperator, PsycStateOp};
|
||||
|
|
124
rust/src/text.rs
Normal file
124
rust/src/text.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use text_types::*;
|
||||
use types::PsycString;
|
||||
use method_types::PsycMethod;
|
||||
use util;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
extern "C" {
|
||||
fn psyc_text_state_init(state: *mut PsycTextState,
|
||||
tmpl: *const c_char,
|
||||
tmplen: usize,
|
||||
buffer: *mut c_char,
|
||||
buflen: usize);
|
||||
|
||||
fn psyc_text_state_init_custom(state: *mut PsycTextState,
|
||||
tmpl_: *const c_char,
|
||||
tmplen: usize,
|
||||
buffer: *mut c_char,
|
||||
buflen: usize,
|
||||
ope: *const c_char,
|
||||
opelen: usize,
|
||||
clo: *const c_char,
|
||||
clolen: usize);
|
||||
|
||||
fn psyc_text_buffer_set(state: *mut PsycTextState,
|
||||
buffer: *mut c_char,
|
||||
length: usize);
|
||||
|
||||
fn psyc_text_bytes_written(state: *const PsycTextState) -> usize;
|
||||
|
||||
fn psyc_text(state: *mut PsycTextState,
|
||||
get_value: extern fn(*const c_void,
|
||||
*const c_char,
|
||||
usize,
|
||||
*mut PsycString)
|
||||
-> PsycTextValueRC,
|
||||
get_value_cls: *const c_void)
|
||||
-> PsycTextRC;
|
||||
|
||||
fn psyc_template(mc: PsycMethod, len: *mut usize) -> *const c_char;
|
||||
}
|
||||
|
||||
extern "C" fn callback(cls: *const c_void,
|
||||
name: *const c_char,
|
||||
namelen: usize,
|
||||
value: *mut PsycString)
|
||||
-> PsycTextValueRC {
|
||||
let get_value: &&for<'a> Fn(&'a [u8]) -> Option<&[u8]> = unsafe {
|
||||
mem::transmute(cls)
|
||||
};
|
||||
let name_slice = unsafe {
|
||||
util::cstring_to_slice(name, namelen)
|
||||
};
|
||||
match get_value(name_slice) {
|
||||
None => PsycTextValueRC::PSYC_TEXT_VALUE_NOT_FOUND,
|
||||
Some(val) => {
|
||||
let mut v: &mut PsycString = unsafe {&mut *value};
|
||||
v.data = val.as_ptr() as *const c_char;
|
||||
v.length = val.len();
|
||||
PsycTextValueRC::PSYC_TEXT_VALUE_FOUND
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Text<'a> {
|
||||
state: PsycTextState,
|
||||
phantom_template: PhantomData<&'a Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<'a> Text<'a> {
|
||||
pub fn new(template: &'a [u8]) -> Self {
|
||||
let mut state: PsycTextState;
|
||||
let template_ptr = template.as_ptr() as *const c_char;
|
||||
unsafe {
|
||||
state = mem::uninitialized();
|
||||
let state_ptr = &mut state as *mut PsycTextState;
|
||||
psyc_text_state_init(state_ptr,
|
||||
template_ptr,
|
||||
template.len(),
|
||||
ptr::null_mut(),
|
||||
0);
|
||||
}
|
||||
Text {
|
||||
state: state,
|
||||
phantom_template: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn substitute_variables<'b, F>(&mut self,
|
||||
get_value: F,
|
||||
buffer: &'b mut [u8])
|
||||
-> SubstitutionResult
|
||||
where F: Fn(&'a [u8]) -> Option<&[u8]> {
|
||||
let state_ptr = &mut self.state as *mut PsycTextState;
|
||||
let buffer_ptr = buffer.as_mut_ptr() as *mut c_char;
|
||||
let trait_obj: &Fn(&'a [u8]) -> Option<&[u8]> = &get_value;
|
||||
let trait_obj_ptr: *const c_void = unsafe {mem::transmute(&trait_obj)};
|
||||
unsafe {
|
||||
psyc_text_buffer_set(state_ptr, buffer_ptr, buffer.len());
|
||||
let result = psyc_text(state_ptr, callback, trait_obj_ptr);
|
||||
match result {
|
||||
PsycTextRC::PSYC_TEXT_NO_SUBST => SubstitutionResult::NoSubstitution,
|
||||
PsycTextRC::PSYC_TEXT_COMPLETE => SubstitutionResult::Complete {
|
||||
bytes_written: psyc_text_bytes_written(state_ptr)
|
||||
},
|
||||
PsycTextRC::PSYC_TEXT_INCOMPLETE => SubstitutionResult::Incomplete {
|
||||
bytes_written: psyc_text_bytes_written(state_ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn template(method: PsycMethod) -> &'static [u8] {
|
||||
let mut result: PsycString;
|
||||
unsafe {
|
||||
result = mem::uninitialized();
|
||||
result.data = psyc_template(method, &mut result.length as *mut usize);
|
||||
util::cstring_to_slice(result.data, result.length)
|
||||
}
|
||||
}
|
||||
}
|
41
rust/src/text_types.rs
Normal file
41
rust/src/text_types.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use types::PsycString;
|
||||
|
||||
#[repr(C)]
|
||||
pub enum PsycTextRC {
|
||||
/// No substitution was made, nothing was written to the buffer.
|
||||
PSYC_TEXT_NO_SUBST = -1,
|
||||
/// Text template parsing & rendering complete.
|
||||
PSYC_TEXT_COMPLETE = 0,
|
||||
/// Text template parsing & rendering is incomplete, because the buffer was too
|
||||
/// small. Another call is required to this function after setting a new buffer.
|
||||
PSYC_TEXT_INCOMPLETE = 1,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum PsycTextValueRC {
|
||||
/// Value not found, don't substitute anything.
|
||||
PSYC_TEXT_VALUE_NOT_FOUND = -1,
|
||||
/// Value found, substitute contents of the value variable.
|
||||
PSYC_TEXT_VALUE_FOUND = 0,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PsycTextState {
|
||||
cursor: usize, ///< current position in the template
|
||||
written: usize, ///< number of bytes written to buffer
|
||||
tmpl: PsycString, ///< input buffer with text template to parse
|
||||
buffer: PsycString, ///< output buffer for rendered text
|
||||
open: PsycString,
|
||||
close: PsycString,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SubstitutionResult {
|
||||
NoSubstitution,
|
||||
Complete {
|
||||
bytes_written: usize
|
||||
},
|
||||
Incomplete {
|
||||
bytes_written: usize
|
||||
}
|
||||
}
|
|
@ -20,6 +20,13 @@ pub struct PsycString {
|
|||
pub data: *const c_char
|
||||
}
|
||||
|
||||
//#[derive(Debug)]
|
||||
//#[repr(C)]
|
||||
//pub struct MutablePsycString {
|
||||
// pub length: usize,
|
||||
// pub data: *mut c_char
|
||||
//}
|
||||
|
||||
impl PsycBool {
|
||||
pub fn to_bool(self) -> bool {
|
||||
match self {
|
||||
|
|
62
rust/tests/test_text.rs
Normal file
62
rust/tests/test_text.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
extern crate psyc;
|
||||
|
||||
use psyc::*;
|
||||
|
||||
#[test]
|
||||
fn test_substitute() {
|
||||
let template = b"Your hello is [_hello]";
|
||||
let mut t = Text::new(template);
|
||||
|
||||
let mut buffer = vec![0; 100];
|
||||
|
||||
let result = t.substitute_variables(|name| {
|
||||
println!("in callback, name: {:?}", name);
|
||||
match name {
|
||||
b"_hello" => Some(b"hi"),
|
||||
_ => None
|
||||
}},
|
||||
&mut buffer);
|
||||
|
||||
assert_eq!(result, SubstitutionResult::Complete {bytes_written: 16});
|
||||
assert_eq!(&buffer[.. 16], b"Your hello is hi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
let mut t = Text::new(b"");
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
assert_eq!(t.substitute_variables(|_name| {Some(b"hi")}, &mut buffer),
|
||||
SubstitutionResult::NoSubstitution);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_incomplete() {
|
||||
let template = b"Your hello is [_hello]";
|
||||
let mut t = Text::new(template);
|
||||
|
||||
let mut buffer = vec![0; 10];
|
||||
|
||||
assert_eq!(t.substitute_variables(|_name| {Some(b"hi")}, &mut buffer),
|
||||
SubstitutionResult::Incomplete {bytes_written: 0});
|
||||
|
||||
buffer.resize(15, 0);
|
||||
|
||||
assert_eq!(t.substitute_variables(|_name| {Some(b"hi")}, &mut buffer),
|
||||
SubstitutionResult::Incomplete {bytes_written: 14});
|
||||
|
||||
buffer.resize(16, 0);
|
||||
assert_eq!(t.substitute_variables(|_name| {Some(b"hi")}, &mut buffer[14 ..]),
|
||||
SubstitutionResult::Complete {bytes_written: 2});
|
||||
|
||||
assert_eq!(&buffer, b"Your hello is hi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_template() {
|
||||
let template = Text::template(PsycMethod::PSYC_MC_REQUEST_CONTEXT_ENTER);
|
||||
let expected: &'static [u8] = b"[_source] asks for your permission to enter [_context]";
|
||||
|
||||
assert_eq!(template, expected);
|
||||
}
|
Loading…
Reference in a new issue